﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using SPMS.Log.Formatter;
using SPMS.Log.Core;

namespace SPMS.Log.Appender
{
    /// <summary>
    /// 将日志条目按照一个有序字符串进行记录的日志记录器
    /// </summary>
    /// <remarks>提供了将日志条目按照一个有序字符串进行记录的日志记录器的抽象基类</remarks>
    /// <history>
    /// [zanezeng]               2009/9/28 10:48    创建
    /// </history>
    public abstract class LiteralLogAppender : AbstractLogAppender
    {
        #region ---Constructor

        /// <summary>
        /// 初始化类型<see cref="LiteralLogAppender"/>的新实例
        /// </summary>
        /// <param name="name">当前日志记录器的名称</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/10/10 10:13    创建
        /// </history>
        public LiteralLogAppender( string name )
            : base( name )
        {
        }

        #endregion

        #region ---Protected Method

        /// <summary>
        /// 通知关闭日志输出器
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:06    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 10:53    创建
        /// </history>
        protected override void OnClose()
        {
            //重置日志记录器
            this.Reset();
        }

        /// <summary>
        /// 通知输出给定的日志条目
        /// </summary>
        /// <param name="entry">要输出的日志条目</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/25 15:26    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 10:53    创建
        /// </history>
        protected override void OnAppend( LogEntry entry )
        {
            //写入日志
            this.Formatter.Format( this.TextWriter, entry );
        }

        /// <summary>
        /// 通知准备输出给定的日志条目
        /// </summary>
        /// <param name="entry">要输出的日志条目</param>
        /// <returns>
        /// 	<c>True</c>：允许输出给定的日志条目<br/>
        /// 	<c>False</c>：不允许输出给定的日志条目
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 9:25    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 10:56    创建
        /// </history>
        protected override bool OnBeforeAppend( LogEntry entry )
        {
            //判断文本写入器是否已经准备好
            if (null == this.TextWriter || this.TextWriter.IsClosed)
            {
                //同步
                lock (this.SyncRoot)
                {
                    //判断文本写入器是否已经准备好
                    if (null == this.TextWriter || this.TextWriter.IsClosed)
                    {
                        //如果没有准备好，则准备文本写入器
                        this.TextWriter = this.PrepareTextWriter();
                    }
                }
            }

            //判断日志写入器是否准备完毕
            if (null == this.TextWriter)
            {
                //输出提示信息
                this.ErrorHandler.HandleError( string.Format( Log.Properties.Resources.MSG_APPENDER_TEXTWRITER_REQUIRED, this.Name ) );

                //如果没有准备完毕，则返回取消日志输出
                return false;
            }

            //判断消息格式化器是否准备好
            if (null == this.Formatter)
            {
                //输出提示信息
                this.ErrorHandler.HandleError( string.Format( Log.Properties.Resources.MSG_APPENDER_FORMATTER_REQUIRED, this.Name ) );

                //返回取消日志输出
                return false;
            }

            //调用基类实现
            return base.OnBeforeAppend( entry );
        }

        /// <summary>
        /// 将缓冲区的数据写入到物理数据存储区
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 10:15    创建
        /// </history>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 11:06    创建
        /// </history>
        protected override void Flush()
        {
            try
            {
                //判断是否有日志写入器
                if (null != this.TextWriter)
                {
                    //强制写入日志
                    this.m_TextWriter.Flush();
                }
            }
            catch (Exception ex)
            {
                //记录错误信息
                this.ErrorHandler.HandleError( string.Format( Log.Properties.Resources.MSG_APPENDER_FLUSH_FAILED, this.Name ), ex );
            }
        }

        /// <summary>
        /// 添加日志记录的页头
        /// </summary>
        /// <param name="writer">用于写入页头的文字写入器</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 11:39    创建
        /// </history>
        protected virtual void AppendHeader( TextWriter writer )
        {
            //判断日志格式化器是否设置以及页头是否有效
            if (null != this.Formatter && !string.IsNullOrEmpty( this.Formatter.Header ))
            {
                //写入页头
                writer.WriteLine( this.Formatter.Header );
            }
        }

        /// <summary>
        /// 添加日志记录的页脚
        /// </summary>
        /// <param name="writer">用于写入页脚的文字写入器</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 11:40    创建
        /// </history>
        protected virtual void AppendFooter( TextWriter writer )
        {
            //判断日志格式化器是否设置以及页脚是否有效
            if (null != this.Formatter && !string.IsNullOrEmpty( this.Formatter.Footer ))
            {
                //写入页头
                writer.WriteLine( this.Formatter.Footer );
            }
        }

        /// <summary>
        /// 重置日志记录器
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 11:48    创建
        /// </history>
        protected virtual void Reset()
        {
            //判断日志写入器是否已经设置
            if (null != this.TextWriter)
            {
                //写入日志的页脚
                this.AppendFooter( this.TextWriter );

                //关闭文字写入器
                this.CloseTextWriter();
            }
        }

        /// <summary>
        /// 为给定的日志条目准备输出日志信息的文本写入器
        /// </summary>
        /// <returns>用于接收日志信息的写入器</returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 10:56    创建
        /// </history>
        protected abstract SafeTextWriter PrepareTextWriter();

        #endregion

        #region ---Property

        /// <summary>
        /// 获得或者设置日志信息格式化器
        /// </summary>
        /// <value>日志信息格式化器</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 11:36    创建
        /// </history>
        public IFormatter Formatter
        {
            get
            {
                //判断消息格式化器是否设置
                if (null == this.m_Formatter)
                {
                    //使用默认的消息格式化器
                    return SimpleFormatter.Default;
                }

                //返回设置的消息格式化器
                return this.m_Formatter;
            }
            set
            {
                this.m_Formatter = value;
            }
        }

        /// <summary>
        /// 获得或者设置用于输出日志的文字写入器
        /// </summary>
        /// <value>用于输出日志的文字写入器</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 11:41    创建
        /// </history>
        protected SafeTextWriter TextWriter
        {
            get
            {
                return this.m_TextWriter;
            }
            private set
            {
                //设置文字写入器
                this.SetTextWriter( value );
            }
        }

        /// <summary>
        /// 获得同步对象
        /// </summary>
        /// <value>同步对象</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2010/1/6 10:36    创建
        /// </history>
        protected object SyncRoot
        {
            get
            {
                return this.m_SyncRoot;
            }
        }

        #endregion

        #region ---Private Method

        /// <summary>
        /// 设置文字写入器
        /// </summary>
        /// <param name="writer">要设置的文字写入器</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 11:50    创建
        /// </history>
        private void SetTextWriter( SafeTextWriter writer )
        {
            //判断判断文字写入是否为同一个实例
            if (object.ReferenceEquals( this.m_TextWriter, writer ))
            {
                //如果是同一个实例，则直接返回
                return;
            }

            //重置日志记录器
            this.Reset();

            //记录日志记录器
            this.m_TextWriter = writer;

            //判断日志记录器是否有效
            if (null != writer)
            {
                //写入日志页头
                this.AppendHeader( writer );
            }
        }

        /// <summary>
        /// 关闭文字写入器
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/28 11:52    创建
        /// </history>
        private void CloseTextWriter()
        {
            //判断日志写入器是否已经准备
            if (null != this.m_TextWriter)
            {
                //关闭文本写入器
                this.m_TextWriter.Close();

                //清除日志写入器
                this.m_TextWriter = null;
            }
        }

        #endregion

        #region ---Field

        /// <summary>
        /// 用于接收日志信息的写入器
        /// </summary>
        private SafeTextWriter m_TextWriter;

        /// <summary>
        /// 日志信息格式化器
        /// </summary>
        private IFormatter m_Formatter;

        /// <summary>
        /// 同步对象
        /// </summary>
        private object m_SyncRoot = new object();

        #endregion
    }
}
